﻿using System;
using HK.Core.Extend;
using HK.Core.GUIEx.Protocol.Attribute;
using HK.Editor.Common;
using HK.Editor.GUIEx.Drag;
using HK.Editor.GUIEx.Drawer;
using HK.Editor.GUIEx.Protocol;
using HK.Editor.GUIEx.Protocol.Drag;
using HK.Editor.GUIEx.Styles;
using HK.Editor.Utils;
using UnityEditor;
using UnityEngine;
using Object = UnityEngine.Object;

namespace HK.Editor.Serializable.Drawer
{
    /// <summary>
    /// GUI绘制器
    /// </summary>
    /// <typeparam name="TAttribute">Attribute类型</typeparam>
    public abstract class GUIPropertyDrawer<TAttribute> : PropertyDrawer, IGUIPropertyDrawer<TAttribute> 
        where TAttribute : PropertyAttribute, IGUIAttribute
    {

        /// <summary>
        /// 初始化标志位
        /// </summary>
        protected bool Initialized { get; set; } = false;

        /// <summary>
        /// 初始化
        /// </summary>
        protected virtual void Init(Rect iRect)
        {
            // 可拖拽
            if (Draggable)
            {
                DragSurrogate = GenerateDragSurrogate();
            }
        }
        
#region Attribute
        
        private TAttribute _selfAttr = default(TAttribute);
        public TAttribute SelfAttr 
        {
            get
            {
                if (default(TAttribute) != _selfAttr) return _selfAttr;
                if (!ConvertToSelfAttr(attribute))
                {
                    this.Error("SelfAttr::ConvertToSelfAttr() Failed!(Type:{0})", attribute.GetType().Name);
                    return default(TAttribute);
                }
                return _selfAttr;
            }
        }
        
        /// <summary>
        /// 转换成自身Attribute
        /// </summary>
        /// <param name="iAttr">PropertyAttribute</param>
        /// <returns>true:OK; false:NG;</returns>
        private bool ConvertToSelfAttr(PropertyAttribute iAttr)
        {
            if (default(TAttribute) != _selfAttr) return true;
            _selfAttr = iAttr as TAttribute;
            return default(TAttribute) != _selfAttr;
        }

#endregion

#region Options

        protected int Options => SelfAttr?.Options ?? (int)GUIOperateOptions.None;
        
        /// <summary>
        /// 绘制背景
        /// </summary>
        public bool DrawBg => SelfAttr?.DrawBg ?? false;
        
        /// <summary>
        /// 只读
        /// </summary>
        public bool ReadOnly => SelfAttr?.ReadOnly ?? false;
        
        /// <summary>
        /// 可展开
        /// </summary>
        public bool Expandable => SelfAttr?.Expandable ?? false;
        
        /// <summary>
        /// 最小化
        /// </summary>
        public bool Minimize => SelfAttr?.Minimize ?? false;
        
        /// <summary>
        /// 最大化
        /// </summary>
        public bool Maximize => SelfAttr?.Maximize ?? false;
        
        /// <summary>
        /// 可追加
        /// </summary>
        public virtual bool Addable => SelfAttr?.Addable ?? false;
		
        /// <summary>
        /// 可移除
        /// </summary>
        public virtual bool Removable => SelfAttr?.Removable ?? false;
        
        /// <summary>
        /// 可枷锁
        /// </summary>
        public bool Lockable => SelfAttr?.Lockable ?? false;
        
        /// <summary>
        /// 可拖拽
        /// </summary>
        public bool Draggable => SelfAttr?.Draggable ?? false;
        
        /// <summary>
        /// 多行
        /// </summary>
        public bool MultiLine => SelfAttr?.MultiLine ?? false;
		
        /// <summary>
        /// 可点击
        /// </summary>
        public bool Clickable => SelfAttr?.Clickable ?? false;
        
        /// <summary>
        /// 成员资产
        /// <para>* true : 成员为资产对象</para>
        /// </summary>
        public bool MemberAsset => SelfAttr?.MemberAsset ?? false;
        
        /// <summary>
        /// 成员无标题
        /// </summary>
        public bool MemberNoCaption => SelfAttr?.MemberNoCaption ?? false;
        
        /// <summary>
        /// 成员可拖拽
        /// </summary>
        public bool MemberDraggable => SelfAttr?.MemberDraggable ?? false;
        
        /// <summary>
        /// 成员唯一
        /// </summary>
        public bool MemberDistinct => SelfAttr?.MemberDistinct ?? false;
        
        /// <summary>
        /// 可检索
        /// </summary>
        public virtual bool Searchable => SelfAttr?.Searchable ?? false;
        
        /// <summary>
        /// 按Property绘制
        /// </summary>
        public bool DrawProperty => SelfAttr?.DrawProperty ?? false;
        
        /// <summary>
        /// 是否从Unity调用绘制标志位
        /// </summary>
        public bool DrawFromUnity => SelfAttr?.DrawFromUnity ?? false;

        /// <summary>
        /// 展开标志位
        /// </summary>
        public virtual bool IsExpanded
        {
            get => SelfProperty?.isExpanded ?? false;
            protected set
            {
                if(null == SelfProperty) return;
                SelfProperty.isExpanded = value;
            }
        }

#endregion

#region Rect

        /// <summary>
        /// 余白 - 横向
        /// </summary>
        protected static readonly float HorizontalSpacing = EditorConst.HorizontalSpacing;

        /// <summary>
        /// 余白 : 纵向
        /// </summary>
        protected static readonly float VerticalSpacing = EditorConst.VerticalSpacing;

        /// <summary>
        /// 单行高度
        /// </summary>
        protected static readonly float  SingleLineHeight = EditorConst.DefaultLineHeight;
                
        /// <summary>
        /// 头部高度
        /// </summary>
        protected static readonly float  HeaderHeight = SingleLineHeight + VerticalSpacing;

        /// <summary>
        /// Label先头缩进
        /// </summary>
        protected static readonly float LabelIntent = EditorConst.LabelIntent;

        /// <summary>
        /// 展开按钮缩进
        /// </summary>
        protected static readonly float ExpandableIntent = EditorConst.ExpandableIntent;

        /// <summary>
        /// Drag Mark宽度
        /// </summary>
        protected static readonly float DragMarkWidth = EditorConst.DragMarkWidth;

        /// <summary>
        /// 按钮宽度 - 仅是Icon的按钮
        /// </summary>
        protected static readonly float BtnWidthIconOnly = EditorConst.BtnWidthIconOnly;

        /// <summary>
        /// 宽度 - 按钮 - 较短
        /// </summary>
        protected static readonly float BtnWidthShort = EditorConst.BtnWidthShort;

        /// <summary>
        /// 按钮宽度 - 中
        /// </summary>
        protected static readonly float BtnWidthMid = EditorConst.BtnWidthMid;

        /// <summary>
        /// 按钮宽度 - 长
        /// </summary>
        protected static readonly float BtnWidthLong = EditorConst.BtnWidthLong;
                
        /// <summary>
        /// 按钮宽度 - 巨长
        /// </summary>
        public static readonly float BtnWidthMegaLength = EditorConst.BtnWidthLong;

        /// <summary>
        /// 按钮宽度 - Footer按钮
        /// </summary>
        protected static readonly float FooterBtnWidth = EditorConst.FooterBtnWidth;
        
        /// <summary>
        /// 总高度
        /// </summary>
        public float TotalHeight { get; protected set; } = 0.0f;

        /// <summary>
        /// 高度 - Footer
        /// </summary>
        protected virtual float FooterHeight => 0.0f;

        /// <summary>
        /// 取得Property的高度
        /// </summary>
        /// <param name="iProperty">Property</param>
        /// <param name="iLabel">文本</param>
        /// <param name="iIncludeChild">Include Child</param>
        /// <returns>Property的高度</returns>
        protected float GetPropertyHeight(SerializedProperty iProperty, GUIContent iLabel, bool iIncludeChild)
        {
            return EditorGUI.GetPropertyHeight(iProperty, iLabel, iIncludeChild);
        }
        
        /// <summary>
        /// 取得Property的高度
        /// </summary>
        /// <param name="iProperty">Property</param>
        /// <param name="iLabel">文本</param>
        /// <returns>Property的高度</returns>
        public override float GetPropertyHeight(SerializedProperty iProperty, GUIContent iLabel)
        {
            var totalHeight = 0.0f;
            if (!iProperty.isExpanded)
            {
                totalHeight = HeaderHeight;
            }
            else
            {
                totalHeight = HeaderHeight;
                if (DrawFromUnity)
                {
                    totalHeight -= 4;
                }
                totalHeight += 2;

                var elementsTotalHeight = CalcElementsTotalHeight(iProperty, out var oValidCount);
                totalHeight += elementsTotalHeight;

                if (0 < oValidCount)
                {
                    totalHeight += 1;
                }
                totalHeight += 6;
            }
            TotalHeight = totalHeight;
            return TotalHeight; 
        }

        /// <summary>
        /// 计算子节点元素的总共高度
        /// </summary>
        /// <param name="iParent">父节点Property</param>
        /// <param name="oValidCount">有效个数</param>
        /// <returns>子节点元素的总共高度</returns>
        protected virtual float CalcElementsTotalHeight(SerializedProperty iParent, out int oValidCount)
        {
            oValidCount = 0;
            var elementTotalHeight = 0.0f;
            if (null == iParent) return elementTotalHeight;

            var copy = iParent.Copy();
            var end = copy.GetEndProperty();
            var nextVisible = copy.NextVisible(true);

            while (nextVisible && !SerializedProperty.EqualContents(copy, end))
            {
                elementTotalHeight += EditorGUI.GetPropertyHeight(copy, GUIContent.none, copy.isExpanded) + 1;
                nextVisible = copy.NextVisible(false);
                ++oValidCount;
            }
            
            return elementTotalHeight;
        }
        
#endregion
        
#region SerializedProperty

        /// <summary>
        /// 自身序列化Property
        /// </summary>
        public SerializedProperty SelfProperty { get; private set; } = null;

        private int _visibleChildCount = -1;
        /// <summary>
        /// 可见子节点数
        /// <para>* 不包含自身</para>
        /// </summary>
        public int VisibleChildCount
        {
            get
            {
                if (-1 < _visibleChildCount) return _visibleChildCount;

                if (null == SelfProperty)
                {
                    return 0;
                }
                
                _visibleChildCount = 0;
                var copy = SelfProperty.Copy();
                var end = copy.GetEndProperty();
                var nextVisible = copy.NextVisible(true);
                while (nextVisible && !SerializedProperty.EqualContents(copy, end))
                {
                    ++_visibleChildCount;
                    nextVisible = copy.NextVisible(false);
                }
                return _visibleChildCount;
            }
        }
        
        /// <summary>
        /// 初始化序列化Property信息
        /// </summary>
        /// <param name="iSelf">自身Property</param>
        /// <returns>true:OK; false:NG;</returns>
        protected virtual bool InitSerializedProperties(SerializedProperty iSelf)
        {
            if (null == iSelf) return false;
            SelfProperty = iSelf;
            return null != SelfProperty;
        }
        
        /// <summary>
        /// 校验Property是否可展开
        /// </summary>
        /// <param name="iProperty">Property</param>
        /// <returns>true:可展开; false:不可展开;</returns>
        protected bool IsPropertyExpandable(SerializedProperty iProperty)
        {
            if (null == iProperty) return false;
            
            var flg = true;
            switch (iProperty.propertyType)
            {
                case SerializedPropertyType.Integer:
                case SerializedPropertyType.Boolean:
                case SerializedPropertyType.Float:
                case SerializedPropertyType.String:
                case SerializedPropertyType.Color:
                case SerializedPropertyType.ObjectReference:
                case SerializedPropertyType.LayerMask:         // LayerMask 属性。
                case SerializedPropertyType.Enum:
                case SerializedPropertyType.Vector2:
                case SerializedPropertyType.Vector3:
                case SerializedPropertyType.Vector4:
                case SerializedPropertyType.Rect:
                case SerializedPropertyType.Character:
                case SerializedPropertyType.AnimationCurve:
                case SerializedPropertyType.Bounds:
                case SerializedPropertyType.Gradient:           // 渐变属性
                case SerializedPropertyType.Quaternion:         // 四元数
                case SerializedPropertyType.ExposedReference:   // 对场景中另一个对象的引用。这将通过 ExposedReference 类型完成，并解析为某个对象的引用，该对象存在于包含 SerializedProperty 的 SerializedObject 上下文中。
                case SerializedPropertyType.FixedBufferSize:    // 固定缓冲区大小属性。
                case SerializedPropertyType.Vector2Int:
                case SerializedPropertyType.Vector3Int:
                case SerializedPropertyType.RectInt:
                case SerializedPropertyType.BoundsInt:
                case SerializedPropertyType.ManagedReference:
                    flg = false;
                    break;
                case SerializedPropertyType.Generic:
                    break;
                default:
                    this.Error("DrawCaption():Not Support Type!(Name:{0} Type:{1})", SelfProperty.name, SelfProperty.propertyType);
                    break;
            }
            return flg;
        }
        
        /// <summary>
        /// 应用改变
        /// </summary>
        protected void ApplyChanged(SerializedProperty iProperty) 
        {
            if(null == iProperty) return;
            iProperty.serializedObject.ApplyModifiedProperties();
            iProperty.serializedObject.Update();
        }

#endregion
        
#region Content

        /// <summary>
        /// 标题
        /// </summary>
        public GUIContent Caption { get; private set; } = null;

        /// <summary>
        /// 重置标题
        /// </summary>
        /// <param name="iAttr">Attribute</param>
        /// <param name="iProperty">Property</param>
        /// <param name="iLabel">默认标题</param>
        /// <returns>标题</returns>
        protected virtual GUIContent ResetCaption(TAttribute iAttr, SerializedProperty iProperty, GUIContent iLabel)
        {
            var captionTxt = iAttr.Caption;
            if (string.IsNullOrEmpty(captionTxt))
            {
                captionTxt = iProperty.displayName;
            }

            if (string.IsNullOrEmpty(captionTxt))
            {
                captionTxt = iLabel.text;
            }

            // 生成新的Content
            return string.IsNullOrEmpty(iAttr.Icon) ? UtilsGUIEx.CreateGuiContent(captionTxt, iAttr.Tips) :
                UtilsGUIEx.CreateGuiContentWithIcon(iAttr.Caption, iAttr.Icon, iAttr.Tips);
        }

        /// <summary>
        /// 初始化Content
        /// </summary>
        /// <param name="iAttr">Attribute</param>
        /// <param name="iProperty">Property</param>
        /// <param name="iLabel">默认标题</param>
        protected virtual void InitContents(TAttribute iAttr, SerializedProperty iProperty, GUIContent iLabel)
        {
            // 重置标题
            Caption = ResetCaption(iAttr, iProperty, iLabel);
        }

#endregion

        /// <summary>
        /// 背景色
        /// </summary>
        public Color BgColor => _selfAttr?.BgColor ?? Color.clear;
        
#region Drag

        /// <summary>
        /// 拖拽代理
        /// </summary>
        public IDragAndDropSurrogate DragSurrogate { get; protected set; } = null;

        /// <summary>
        /// 创建一个拖拽代理
        /// </summary>
        /// <returns>拖拽代理</returns>
        protected virtual IDragAndDropSurrogate GenerateDragSurrogate() => null;
        
        /// <summary>
        /// 挂接拖拽
        /// </summary>
        /// <param name="iRect">区域</param>
        /// <param name="iEvent">Event</param>
        /// <param name="iProperty">拖拽对象引用列表</param>
        /// <param name="iIsAsset">资产标志位(true:文件/文件夹; false:引用对象;)</param>
        private void HandleDragAndDrop(Rect iRect, Event iEvent, SerializedProperty iProperty, bool iIsAsset) 
        {

            switch (iEvent.GetTypeForControl(DragDropControlID)) 
            {
                // 拖拽更新
                case EventType.DragUpdated:
                // 执行拖拽
                case EventType.DragPerform:
					
                    if (GUI.enabled && iRect.Contains(iEvent.mousePosition)) 
                    {
                        var acceptDrag = false;
                        // 拖动文件或者文件夹
                        if (iIsAsset)
                        {
                            if (null != DragSurrogate && DragSurrogate.Valid)
                            {
                                var paths = DragAndDrop.paths;
                                if (null != paths && 0 < paths.Length)
                                {
                                    DragAndDrop.visualMode = DragAndDropVisualMode.Generic;
                                    acceptDrag = true;

                                    DragSurrogate.DragAndDropDown(paths);
                                }
                            }
                        }
                        else
                        {
							
                            // 拖拽对象引用列表
                            var objectReferences = DragAndDrop.objectReferences;
                            var references = new Object[1];
                            foreach (var object1 in objectReferences) 
                            {
                                references[0] = object1;
                                var object2 = ValidateObjectDragAndDrop(references, iProperty);

                                if (null != object2) 
                                {
                                    DragAndDrop.visualMode = DragAndDropVisualMode.Copy;
                                    if (iEvent.type == EventType.DragPerform) 
                                    {
                                        AppendDragAndDropValue(object2, iProperty);
                                        acceptDrag = true;
                                        DragAndDrop.activeControlID = 0;
                                    }
                                    else 
                                    {
                                        DragAndDrop.activeControlID = DragDropControlID;
                                    }
                                }
                            }
                        }
                        if (acceptDrag) 
                        {
                            GUI.changed = true;
                            DragAndDrop.AcceptDrag();
                            iEvent.Use();
                        }
                    }
                    break;

                case EventType.DragExited:
					
                    if (GUI.enabled) 
                    {
                        HandleUtility.Repaint();
                    }

                    break;
            }
        }
        
        /// <summary>
        /// 验证拖拽对象
        /// </summary>
        /// <param name="iReferences">拖拽对象引用列表</param>
        /// <param name="iProperty">拖拽对象引用列表</param>
        /// <returns>拖拽对象</returns>
        private Object ValidateObjectDragAndDrop(Object[] iReferences, SerializedProperty iProperty) 
        {
            if (null != DragSurrogate && DragSurrogate.Valid) 
            {
                // if we have a surrogate type, then validate using the surrogate type rather than the list
                return DragAndDropValidate.ValidateObjectDragAndDrop(iReferences, null, DragSurrogate.TargetType, DragSurrogate.ExactType);
            }

            return DragAndDropValidate.ValidateObjectDragAndDrop(iReferences, iProperty, null, false);
        }
        
        /// <summary>
        /// 追加脱妆对象
        /// </summary>
        /// <param name="iDragObj">拖拽对象</param>
        /// <param name="iProperty">拖拽对象引用列表</param>
        private void AppendDragAndDropValue(Object iDragObj, SerializedProperty iProperty) 
        {
            // check if we have a surrogate type. If so use that for appending
            if (null != DragSurrogate && DragSurrogate.Valid) 
            {
                DragSurrogate.DragAndDropDown(iDragObj);
            }
            else 
            {
                DragAndDropValidate.AppendDragAndDropValue(iDragObj, iProperty);
            }
        }

#endregion

#region Events

        private int _controlId = -1;
        /// <summary>
        /// 选中的控件Id
        /// </summary>
        public int ControlId
        {
            get => _controlId;
            protected set => _controlId = value;
        }
        
        /// <summary>
        /// 生成Control Id
        /// </summary>
        /// <param name="iRect">当前矩形区域</param>
        /// <param name="iHashCode">Selection Hash Code</param>
        /// <returns>Control Id</returns>
        protected int GenerateControlId(Rect iRect, int iHashCode = -1)
        {
            var hashCode = iHashCode;
            if (-1 == hashCode)
            {
                hashCode = GetType().Name.GetHashCode();
            }
            return UtilsGUIEx.GenerateControlId(iRect, hashCode);
        }
		
        protected virtual int DragAndDropHash => $"{GetType().Name}DragAndDrop".GetHashCode();
        
        /// <summary>
        /// 拖拽Control Id
        /// </summary>
        protected int DragDropControlID { get; set; } = -1;
        
        /// <summary>
        /// 挂接拖拽
        /// </summary>
        /// <param name="iRect">区域</param>
        /// <param name="iEvent">Event</param>
        /// <param name="iOnDragAnDropped">拖拽回调</param>
        protected void HandleDragAndDrop(Rect iRect, Event iEvent, AssetsDragAndDropDown iOnDragAnDropped) 
        {
            switch (iEvent.GetTypeForControl(DragDropControlID)) 
            {
                // 拖拽更新
                case EventType.DragUpdated:
                // 执行拖拽
                case EventType.DragPerform:
                {
                    if (iRect.Contains(iEvent.mousePosition))
                    {
                        var acceptDrag = false;
                        // 拖动文件或者文件夹
                        var paths = DragAndDrop.paths;
                        if (null != paths && 0 < paths.Length)
                        {
                            DragAndDrop.visualMode = DragAndDropVisualMode.Generic;
                            acceptDrag = true;

                            iOnDragAnDropped.Invoke(paths);
                        }
                        
                        if (acceptDrag) 
                        {
                            GUI.changed = true;
                            DragAndDrop.AcceptDrag();
                            iEvent.Use();
                        }
                    }
                }
                    break;
                case EventType.DragExited:
                {
                    if (GUI.enabled) 
                    {
                        HandleUtility.Repaint();
                    }
                }
                    break;
                default:
                    break;
            }
        }

        /// <summary>
        /// 标题展开时间
        /// </summary>
        /// <param name="iRect">绘制矩形区域</param>
        /// <param name="iEvent">Event</param>
        /// <param name="iCaptionProperty">标题Property</param>
        /// <returns>绘制的矩形区域</returns>
        protected virtual Rect OnCaptionExpanded(Rect iRect, Event iEvent, SerializedProperty iCaptionProperty) => iRect;

        /// <summary>
        /// 展开
        /// </summary>
        /// <param name="iSelfProperty">自身Property</param>
        /// <param name="iIsExpanded">展开/缩进</param>
        protected virtual void ExpandChildren(SerializedProperty iSelfProperty, bool iIsExpanded)
        {
            if(null == iSelfProperty) return;
            
            var copy = iSelfProperty.Copy();
            var end = copy.GetEndProperty();
            
            var nextVisible = copy.NextVisible(true);
            while (nextVisible && !SerializedProperty.EqualContents(copy, end))
            {
                copy.isExpanded = iIsExpanded;
                nextVisible = copy.NextVisible(false);
            }
        }
        
        /// <summary>
        /// 挂接所有事件
        /// </summary>
        /// <param name="iEvent">Event</param>
        protected virtual void HandleEvents(Event iEvent) {}
        
        /// <summary>
        /// 判断鼠标左键/中键按下？
        /// </summary>
        /// <param name="iEvent">Event</param>
        /// <returns>true:按下; false:未按下;</returns>
        private bool IsMouseLeftOrMidBtnDown(Event iEvent) 
        {
            // 鼠标左键/中键按下
            return iEvent.button == 0 || iEvent.button == 2;
        }
        
        /// <summary>
        /// 判断鼠标右键按下？
        /// </summary>
        /// <param name="iEvent">Event</param>
        /// <returns>true:按下; false:未按下;</returns>
        private bool IsMouseRightClickDown(Event iEvent) 
        {
            // 鼠标左键/中键按下
            return iEvent.button == 1;
        }
        
        /// <summary>
        /// 鼠标左键点击事件
        /// </summary>
        protected virtual void OnMouseLeftClicked(int iControlId) {}
        
        /// <summary>
        /// 鼠标右键点击事件
        /// </summary>
        protected virtual void OnMouseRightClicked(int iControlId) {}
        
        /// <summary>
        /// 挂接鼠标点击事件
        /// <para>* 为选中Element后，鼠标右键菜单</para>
        /// </summary>
        /// <param name="iRect">Element索引</param>
        /// <param name="iEvent">Event</param>
        /// <param name="iControlId">Control Id</param>
        /// <param name="iOnMouseLeftClicked">鼠标左键点击回调</param>
        /// <param name="iOnMouseRightClicked">鼠标右键点击回调</param>
        protected void HandleMouseEvents(Rect iRect, Event iEvent, int iControlId,
            Action<int> iOnMouseLeftClicked = null, Action<int> iOnMouseRightClicked = null)
        {
            switch (iEvent.GetTypeForControl(ControlId))
            {
                // 拖拽更新
                case EventType.MouseDown:
                case EventType.MouseUp:
                {
                    // 鼠标左键/中键事件
                    if (iRect.Contains(iEvent.mousePosition) && IsMouseLeftOrMidBtnDown(iEvent))
                    {
                        if (null == iOnMouseLeftClicked)
                        {
                            OnMouseLeftClicked(iControlId);
                        }
                        else
                        {
                            iOnMouseLeftClicked.Invoke(iControlId);   
                        }
                        iEvent.Use();
                    }
			        
                    // 鼠标邮件时间
                    if (iRect.Contains(iEvent.mousePosition) && IsMouseRightClickDown(iEvent))
                    {
                        if (null == iOnMouseRightClicked)
                        {
                            OnMouseLeftClicked(iControlId);
                        }
                        else
                        {
                            iOnMouseRightClicked.Invoke(iControlId);
                        }
                        iEvent.Use();
                    }
                }
                    break;
                default:
                    break;
            } 
        }
        
#endregion

#region Draw
        
        /// <summary>
        /// 绘制GUI
        /// </summary>
        /// <param name="iRect">绘制矩形区域</param>
        /// <param name="iProperty">Property</param>
        /// <param name="iLabel">标题</param>
        public override void OnGUI(Rect iRect, SerializedProperty iProperty, GUIContent iLabel)
        {
            // 初始化
            InitSerializedProperties(iProperty);
            InitContents(SelfAttr, SelfProperty, iLabel);
            
            if (!Initialized)
            {
                Init(iRect);
                Initialized = true;
            }
            
            // 控件Id
            ControlId = GenerateControlId(iRect);
            DragDropControlID = UtilsGUIEx.GenerateDragControlId(iRect, DragAndDropHash);
            
            // 当前Event
            var curEvent = Event.current;
            
            // 绘制标题
            var captionRect = iRect;
            captionRect.yMin += 2;
            captionRect.height = HeaderHeight;
            captionRect = DrawCaption(captionRect, curEvent, Caption);
            
            // 只读
            var lastEnable = GUI.enabled;
            if (ReadOnly)
            {
                GUI.enabled = false;
            }

            if (!Expandable || !IsExpanded)
            {
                GUI.enabled = lastEnable;
                return;
            }
            
            // 绘制自身
            if (0 < VisibleChildCount)
            {
                var selfBgRect = iRect;
                selfBgRect.yMin = captionRect.yMax - 2;
                selfBgRect.yMax -= 2;
                selfBgRect.xMin += HorizontalSpacing;
                selfBgRect.xMax -= HorizontalSpacing;
                selfBgRect = DrawGenericBg(selfBgRect, curEvent);
                
                var selfRect = selfBgRect;
                selfRect.yMin = selfBgRect.yMin + 1;
                selfRect.yMax -= (FooterHeight + 2);
                selfRect = DrawSelf(selfRect, curEvent);

                if (0.0f < FooterHeight)
                {
                    var footerRect = selfRect;
                    footerRect.yMin = selfRect.yMax;
                    footerRect.yMax = footerRect.yMin + FooterHeight;
                    footerRect = DrawFooter(footerRect, curEvent);
                }
            }
            
            GUI.enabled = lastEnable;
            
            // 挂接所有事件
            if (lastEnable && 0 < VisibleChildCount)
            {
                HandleEvents(curEvent);
            }
        }

        /// <summary>
        /// 绘制GUI
        /// </summary>
        /// <param name="iRect">绘制矩形区域</param>
        /// <param name="iEvent">Event</param>
        /// <returns>绘制范围</returns>
        protected virtual Rect DrawSelf(Rect iRect, Event iEvent)
        {
            var displayRect = iRect;
            if (!IsExpanded) return displayRect;
            
            var dragMarkRect = displayRect;
            dragMarkRect.y = displayRect.yMin + VerticalSpacing;
            dragMarkRect.width = DragMarkWidth;
            dragMarkRect.height = SingleLineHeight;
            dragMarkRect = UtilsGUIEx.DrawDragMark(dragMarkRect, iEvent);
            
            var bodyBgRect = displayRect;
            bodyBgRect.xMin = dragMarkRect.xMax + HorizontalSpacing;
            bodyBgRect.xMax -= HorizontalSpacing;
            bodyBgRect.yMin = displayRect.yMin + 1;
            bodyBgRect.yMax = displayRect.yMax;
            bodyBgRect = UtilsGUIEx.DrawGenericBg(bodyBgRect, iEvent);

            var elementsRect = bodyBgRect;
            elementsRect.xMin += HorizontalSpacing;
            elementsRect.xMax -= HorizontalSpacing;
            elementsRect.yMin += VerticalSpacing;
            elementsRect.yMax -= 1;
            elementsRect = DrawElements(elementsRect, iEvent, SelfProperty);

            return displayRect;
        }

        /// <summary>
        /// 绘制底部
        /// </summary>
        /// <param name="iRect"></param>
        /// <param name="iEvent"></param>
        /// <returns></returns>
        protected virtual Rect DrawFooter(Rect iRect, Event iEvent) => iRect;

#region Caption

        /// <summary>
        /// 绘制标题
        /// </summary>
        /// <param name="iRect">绘制矩形区域</param>
        /// <param name="iEvent">Event</param>
        /// <param name="iCaption">标题</param>
        /// <returns>绘制的矩形区域</returns>
        protected virtual Rect DrawCaption(Rect iRect, Event iEvent, GUIContent iCaption)
        {
            var displayRect = iRect;
            if (null == SelfProperty)
            {
                this.Error("DrawCaption():The property of self is null!");
                return displayRect;
            }

            if (iCaption.text.StartsWith("拆分结果"))
            {
                int i = 0;
            }
            
            // 标题区域
            var titleRect = displayRect;
            titleRect.y -= VerticalSpacing;
            titleRect.xMin += Expandable ? ExpandableIntent : LabelIntent;
            var captionTmp = EditorGUI.BeginProperty(titleRect, iCaption, SelfProperty);
            if (Expandable)
            {
                // 展开
                if (IsExpanded)
                {
                    var bgRect = displayRect;
                    bgRect.xMin += HorizontalSpacing;
                    bgRect.xMax -= HorizontalSpacing;
                    bgRect.height = HeaderHeight;
                    bgRect = DrawGenericBg(bgRect, iEvent);
                }
                else
                {
                    titleRect.y -= 1;
                }

                EditorGUI.BeginChangeCheck();
                // 绘制折叠标题
                var isExpanded = EditorGUI.Foldout(titleRect, IsExpanded, captionTmp, false);
                if (EditorGUI.EndChangeCheck()) 
                {
                    IsExpanded = isExpanded;
                    OnCaptionExpanded(titleRect, iEvent, SelfProperty);
                }
            }
            else
            {
                if (DrawProperty && SelfAttr is IGUIAttribute)
                {
                    EditorGUI.PropertyField(titleRect, SelfProperty, captionTmp);
                }
                else
                {
                    switch (SelfProperty.propertyType)
                    {
                        case SerializedPropertyType.String:
                            EditorGUI.LabelField(titleRect, Caption.text, SelfProperty.stringValue);
                            break;
                        case SerializedPropertyType.Integer:
                            EditorGUI.LabelField(titleRect, Caption.text, $"{SelfProperty.intValue}");
                            break;
                        case SerializedPropertyType.Enum:
                            EditorGUI.LabelField(titleRect, Caption.text, $"{SelfProperty.enumDisplayNames[SelfProperty.enumValueIndex]}");
                            break;
                        case SerializedPropertyType.Boolean:
                            EditorGUI.LabelField(titleRect, Caption.text, $"{SelfProperty.boolValue}");
                            break;
                        case SerializedPropertyType.Float:
                            EditorGUI.LabelField(titleRect, Caption.text, $"{SelfProperty.floatValue}");
                            break;
                        case SerializedPropertyType.AnimationCurve:
                            if (ReadOnly)
                            {
                                EditorGUI.PropertyField(titleRect, SelfProperty, captionTmp);
                            }
                            else
                            {
                                var displayRectTmp = titleRect;
                                displayRectTmp.x += 10;
                                EditorGUI.BeginChangeCheck();
                                IsExpanded = EditorGUI.Foldout(displayRectTmp, IsExpanded, Caption.text);
                                if (EditorGUI.EndChangeCheck())
                                {
                                    OnCaptionExpanded(titleRect, iEvent, SelfProperty);
                                }
                            }
                            break;
                        case SerializedPropertyType.Generic:
                        {
                            EditorGUI.LabelField(titleRect, Caption.text);
                        }
                            break;
                        default:
                            this.Error("DrawCaption():Not Support Type!(Name:{0} Type:{1})", SelfProperty.name, SelfProperty.propertyType);
                            break;
                    }
                }
            }

            var captionOptionsRect = DrawCaptionOptions(displayRect, iEvent);
            
            EditorGUI.EndProperty();
            return displayRect;
        }

        /// <summary>
        /// 绘制标题选项
        /// </summary>
        /// <param name="iRect">绘制矩形区域</param>
        /// <param name="iEvent">Event</param>
        /// <returns>绘制的矩形区域</returns>
        protected virtual Rect DrawCaptionOptions(Rect iRect, Event iEvent)
        {
            var displayRect = iRect;
            // 最大化
            var maxBtnRect = displayRect;
            if (Maximize)
            {
                maxBtnRect.xMax = displayRect.xMax - HorizontalSpacing - 1;
                maxBtnRect.xMin = maxBtnRect.xMax - BtnWidthIconOnly;
                if (GUI.Button(maxBtnRect, GuiExHelper.MaxWinBtn, GuiExHelper.PreButtonStretch)) 
                {
                    ExpandChildren(SelfProperty, true);
                }
            }

            // 最小化
            var minBtnRect = maxBtnRect;
            minBtnRect.yMin += 1;
            minBtnRect.yMax -= VerticalSpacing;
            if (Minimize)
            {
                minBtnRect.xMax = maxBtnRect.xMin - 1;
                minBtnRect.xMin = minBtnRect.xMax - BtnWidthIconOnly;
            
                // 不展开按钮 - 右上角最小化按钮
                if (GUI.Button(minBtnRect, GuiExHelper.MinWinBtn, GuiExHelper.PreButtonStretch)) 
                {
                    ExpandChildren(SelfProperty, false);
                }
            }

            displayRect.xMin = minBtnRect.xMin;
            return displayRect;
        }

#endregion

#region Children
        
        /// <summary>
        /// 绘制子节点
        /// </summary>
        /// <param name="iRect">绘制矩形区域</param>
        /// <param name="iEvent">Event</param>
        /// <param name="iSelf">自身Property</param>
        /// <returns>绘制范围</returns>
        protected virtual Rect DrawElements(Rect iRect, Event iEvent, SerializedProperty iSelf)
        {
            var displayRect = iRect;
            if (null == iSelf) return displayRect;
            
            // 非数组元素
            var copy = iSelf.Copy();
            var end = copy.GetEndProperty();
            
            var childRect = displayRect;
            childRect.height = EditorGUI.GetPropertyHeight(copy);
            
            var nextVisible = copy.NextVisible(true);
            while (nextVisible && !SerializedProperty.EqualContents(copy, end)) 
            {

#if UGUIEX_DEBUG
                if (SpPaginationDrawer.TempFlg && copy.name.Equals("body"))
                {
                    var prefabConfProperty = copy.FindPropertyRelative("prefabConf");
                    var splitListProperty = prefabConfProperty.FindPropertyRelative("splitList");
                    var listProperty = splitListProperty.FindPropertyRelative("list");
                    var arraySize = listProperty.arraySize;
                    this.Error("DrawElements():Size:{0}", arraySize);
                    SpPaginationDrawer.TempFlg = false;
                }
#endif
                
                //if (copy.hasVisibleChildren)
                {
                    childRect.height = EditorGUI.GetPropertyHeight(copy);
                    childRect = UtilsGUIEx.DrawProperty(childRect, iEvent, copy, 
                        null, null, (int)GUIOperateOptions.DrawBg);
                    childRect.y = childRect.yMax + 1;
                }
                nextVisible = copy.NextVisible(false);
            }
                    
            return displayRect;
        }

#endregion

#region Background

        /// <summary>
        /// 绘制背景 - 一般
        /// </summary>
        /// <param name="iRect">绘制矩形区域</param>
        /// <param name="iEvent">Event</param>
        /// <returns>绘制的矩形区域</returns>
        protected Rect DrawGenericBg(Rect iRect, Event iEvent)
        {
            return UtilsGUIEx.DrawGenericBg(iRect, iEvent, Options);
        }

        /// <summary>
        /// 绘制背景
        /// </summary>
        /// <param name="iRect">绘制矩形区域</param>
        /// <param name="iEvent">Event</param>
        /// <param name="iBgColor">背景色</param>
        /// <param name="iStyle">背景Style</param>
        /// <returns>绘制的矩形区域</returns>
        protected Rect DrawGenericBg(Rect iRect, Event iEvent, Color iBgColor, GUIStyle iStyle)
        {
            return UtilsGUIEx.DrawGenericBg(iRect, iEvent, iBgColor, iStyle, false, false, Options);
        }
        
        /// <summary>
        /// 绘制背景 - 一般
        /// </summary>
        /// <param name="iRect">绘制矩形区域</param>
        /// <param name="iEvent">Event</param>
        /// <param name="iStyle">背景Style</param>
        /// <returns>绘制的矩形区域</returns>
        protected Rect DrawGenericBg(Rect iRect, Event iEvent, GUIStyle iStyle)
        {
            return DrawGenericBg(iRect, iEvent, BgColor, iStyle);
        }
        
        /// <summary>
        /// 绘制背景 - 可点击
        /// </summary>
        /// <param name="iRect">绘制矩形区域</param>
        /// <param name="iEvent">Event</param>
        /// <returns>绘制的矩形区域</returns>
        protected Rect DrawClickableBg(Rect iRect, Event iEvent)
        {
            return DrawGenericBg(iRect, iEvent, UtilsGUIEx.ColorClickable, GuiExHelper.HeaderBackground);
        }
        
        /// <summary>
        /// 绘制背景 - 可拖拽
        /// </summary>
        /// <param name="iRect">绘制矩形区域</param>
        /// <param name="iEvent">Event</param>
        /// <returns>绘制的矩形区域</returns>
        protected Rect DrawDraggableBg(Rect iRect, Event iEvent)
        {
            return DrawGenericBg(iRect, iEvent, UtilsGUIEx.ColorDraggable, GuiExHelper.HeaderBackground);
        }

#endregion

#endregion
        
    }
}
